import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
// import { initScene } from './frame-worker.js'
import { initScene } from '../frame.js'

export function initThreeInWorker({ canvas, inputElement }) {
  const scene = initScene({ canvas }, inputElement)

  const controls = new OrbitControls(scene.my.camera, inputElement)
  controls.target.set(0, 0, 0)
  controls.update()

  {
    const color = 0xffffff
    const intensity = 3
    const light = new THREE.DirectionalLight(color, intensity)
    light.position.set(-1, 2, 4)
    scene.add(light)
  }

  const boxWidth = 1
  const boxHeight = 1
  const boxDepth = 1
  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth)

  function makeInstance(geometry, color, x) {
    const material = new THREE.MeshPhongMaterial({
      color,
    })

    const cube = new THREE.Mesh(geometry, material)
    scene.add(cube)

    cube.position.x = x

    return cube
  }

  const cubes = [
    makeInstance(geometry, 0x44aa88, 0),
    makeInstance(geometry, 0x8844aa, -2),
    makeInstance(geometry, 0xaa8844, 2),
  ]

  class PickHelper {
    constructor() {
      this.raycaster = new THREE.Raycaster()
      this.pickedObject = null
      this.pickedObjectSavedColor = 0
    }
    pick(normalizedPosition, scene, camera, time) {
      // restore the color if there is a picked object
      if (this.pickedObject) {
        this.pickedObject.material.emissive.setHex(this.pickedObjectSavedColor)
        this.pickedObject = undefined
      }

      // cast a ray through the frustum
      this.raycaster.setFromCamera(normalizedPosition, camera)
      // get the list of objects the ray intersected
      const intersectedObjects = this.raycaster.intersectObjects(scene.children)
      if (intersectedObjects.length) {
        // pick the first object. It's the closest one
        this.pickedObject = intersectedObjects[0].object
        // save its color
        this.pickedObjectSavedColor = this.pickedObject.material.emissive.getHex()
        // set its emissive color to flashing red/yellow
        this.pickedObject.material.emissive.setHex((time * 8) % 2 > 1 ? 0xffff00 : 0xff0000)
      }
    }
  }

  const pickPosition = { x: -2, y: -2 }
  const pickHelper = new PickHelper()
  clearPickPosition()

  function getCanvasRelativePosition(event) {
    const rect = inputElement.getBoundingClientRect()
    return {
      x: event.clientX - rect.left,
      y: event.clientY - rect.top,
    }
  }

  function setPickPosition(event) {
    const pos = getCanvasRelativePosition(event)
    pickPosition.x = (pos.x / inputElement.clientWidth) * 2 - 1
    pickPosition.y = (pos.y / inputElement.clientHeight) * -2 + 1 // note we flip Y
  }

  function clearPickPosition() {
    // unlike the mouse which always has a position
    // if the user stops touching the screen we want
    // to stop picking. For now we just pick a value
    // unlikely to pick something
    pickPosition.x = -100000
    pickPosition.y = -100000
  }

  inputElement.addEventListener('mousemove', setPickPosition)
  inputElement.addEventListener('mouseout', clearPickPosition)
  inputElement.addEventListener('mouseleave', clearPickPosition)

  inputElement.addEventListener(
    'touchstart',
    (event) => {
      // prevent the window from scrolling
      event.preventDefault()
      setPickPosition(event.touches[0])
    },
    { passive: false },
  )

  inputElement.addEventListener('touchmove', (event) => {
    setPickPosition(event.touches[0])
  })

  inputElement.addEventListener('touchend', clearPickPosition)

  scene.my.preRender.push((time) => {
    pickHelper.pick(pickPosition, scene, scene.my.camera, time)
    time *= 0.001
    cubes.forEach((cube, ndx) => {
      const speed = 1 + ndx * 0.1
      const rot = time * speed
      cube.rotation.x = rot
      cube.rotation.y = rot
    })
  })
}
